#pragma once

#include <list>
#include <vector>
#include <unordered_map>
#include "RPCActor.h"

class RPCManager
{
    friend class RPCActor;
public:
    RPCManager();
    ~RPCManager();

    void TickObjs();

    void OnRPCReply(INetPacket *pck);

    void SendAllRequests(RPCActor *actor);
    void InterruptAllRequests(RPCActor *actor);
    void InterruptRequest(uint64 requestSN);

    size_t GetWaitReplyRequests();

private:
    class RPCAsyncTask;
    struct TickInfo {
        uint64 sn;
        time_t expiry;
        const uintptr_t actor;
    };
    struct RequestInfo {
        INetPacket *trans, *pck;
        std::string args;
        std::function<void(INetStream&, int32, bool)> cb;
        std::weak_ptr<AsyncTaskOwner> owner;
        std::time_t timeout;
        std::size_t slot;
        std::list<TickInfo>::iterator itr;
        std::shared_ptr<std::atomic<uintptr_t>> hinder;
    };

    int DoReply(INetPacket *pck, const RPCActor::ReplyMetaInfo &info);

    void PutRequestInfo(RPCActor *actor,
        uint64 requestSN, std::shared_ptr<RequestInfo> &&requestInfoPtr);

    void RemoveTickObj(RequestInfo &info);
    void RelocateTickObj(RequestInfo &info,
        std::list<TickInfo> &other, std::list<TickInfo>::iterator itr);

    std::vector<std::list<TickInfo>> tick_objs_;
    std::time_t tick_time_;
    std::unordered_map<uint64, std::shared_ptr<RequestInfo>> requests_;
    std::atomic<uint64> request_sn_;
    std::mutex mutex_;

    static std::weak_ptr<AsyncTaskOwner> null_owner_;
    static ConstNetPacket null_packet_;
};
